import json

class Node:
    def __init__(self,left=None,right=None,op=None) -> None:
        self.left = left
        self.right = right
        self.op = op

    def __str__(self) -> str:
        return '%s left:%s right:%s'%(self.op,self.left,self.right)

class AstNode(Node):
    def __init__(self,left=None,right=None,op=None,parent=None,line=None) -> None:
        self.parent=parent
        self.line=line
        super().__init__(left,right,op)
    parent=None
    line=None

    def __str__(self) -> str:
        return 'AstNode: '+self.op

class Data:
    value=None

class jFloat(Data):
    def __init__(self,value=None) -> None:
        self.value=0.0 if value is None else float(value)

    def add(self,data):
        if isinstance(data,jFloat) or isinstance(data,jInt):
            return jFloat(self.value+data.value)
        elif isinstance(data,jString):
            return jString(str(self.value)+data.value)
        else:
            raise Exception('cannot add float and '+type(data))

    def sub(self,data):
        if isinstance(data,jFloat) or isinstance(data,jInt):
            return jFloat(self.value-data.value)
        else:
            raise Exception('cannot sub float and '+type(data))

    def mul(self,data):
        if isinstance(data,jFloat) or isinstance(data,jInt):
            return jFloat(self.value*data.value)
        else:
            raise Exception('cannot mul float and '+type(data))

    def div(self,data):
        if isinstance(data,jFloat) or isinstance(data,jInt):
            if data.value==0:
                raise Exception('cannot div 0')
            return jFloat(self.value/data.value)
        else:
            raise Exception('cannot div float and '+type(data))

    def __str__(self) -> str:
        return str(self.value)

class jInt(Data):
    def __init__(self,value=None) -> None:
        if value is None:
            self.value=0
        elif isinstance(value,int) or isinstance(value,float):
            self.value=int(value)
        elif (value.isnumeric()):
            self.value=int(value)
        elif value[0]=='0':
            sca=value[1].tolower()
            if sca=='x':
                self.value=int(value,16)
            elif sca=='b':
                self.value=int(value,2)
            elif sca=='o':
                self.value=int(value,8)
            else: raise ValueError('invalid number')
        else:
            raise ValueError('invalid number')

    def toFloat(self,value:str)->jFloat:
        if value.isnumeric():
            return jFloat(str(self.value)+"."+value)
        elif value.find('e')>0:
            arr=value.split('e')
            return jFloat(float(str(self.value)+"."+arr[0])*(10**int(arr[1])))
        else:
            raise ValueError('invalid number:'+str(self.value)+'.'+value)

    def add(self,data):
        if isinstance(data,jInt):
            return jInt(self.value+data.value)
        elif isinstance(data,jFloat):
            return jFloat(self.value+data.value)
        elif isinstance(data,jString):
            return jString(str(self.value)+data.value)
        else:
            raise Exception('cannot add int and '+type(data))

    def sub(self,data):
        if isinstance(data,jInt):
            return jInt(self.value-data.value)
        elif isinstance(data,jFloat):
            return jFloat(self.value-data.value)
        else:
            raise Exception('cannot sub int and '+type(data))

    def mul(self,data):
        if isinstance(data,jInt):
            return jInt(self.value*data.value)
        elif isinstance(data,jFloat):
            return jFloat(self.value*data.value)
        else:
            raise Exception('cannot mul int and '+type(data))

    def div(self,data):
        if isinstance(data,jInt):
            if data.value==0:
                raise Exception('cannot div 0')
            return jInt(self.value/data.value)
        elif isinstance(data,jFloat):
            if data.value==0:
                raise Exception('cannot div 0')
            return jFloat(self.value/data.value)
        else:
            raise Exception('cannot div int and '+type(data))

    def __str__(self) -> str:
        return str(self.value)

class jArray(Data):
    def __init__(self,value=None) -> None:
        self.value=value

    def __str__(self) -> str:
        return json.dumps(self.value)

class jObj(Data):
    def __init__(self,value=None) -> None:
        self.value=value

    def __str__(self) -> str:
        return json.dumps(self.value)

class jString(Data):
    def __init__(self,value=None) -> None:
        self.value=value

    def add(self,data):
        return jString(self.value+str(data.value))

    def __str__(self) -> str:
        return self.value

class jVar(Data):
    def __init__(self,value=None,opt=None) -> None:
        self.value=value
        self.opt=opt

    def __str__(self) -> str:
        return f'var {self.value}'

class jBool(Data):
    def __init__(self,value=None) -> None:
        self.value=value

    def __str__(self) -> str:
        return f'{self.value}'

class jNull(Data):
    def __init__(self) -> None:
        self.value=None

    def __str__(self) -> str:
        return 'null'